<!DOCTYPE html>

<html>

	<head>
		<style>
			body {
				/* set margin to 0 and overflow to hidden, to go fullscreen */
				margin: 0;
				overflow: hidden;
				background-color: #000000;
			}
		</style>

		<title>Lane-Assist-Prototyp_a01</title>
		<!--Include von Three.js-->
		<script type="text/javascript" src="libs/three.js"></script>
		<!--Include von Statsjs zur Kontrolle der FPS-->
		<script type="text/javascript" src="libs/stats.js"></script>
		<!--Include von Physijs zur Physiksimulation-->
		<script type="text/javascript" src="libs/physi.js"></script>
		<!--Include von DatGui zur Kontrolle der Eingabeparameter-->
		<script type="text/javascript" src="libs/dat.gui.js"></script>
		<!-- Include der Chroma.js-Libary zur Farbverwaltung-->
		<script type="text/javascript" src="libs/chroma.js"></script>
		<!-- Include spezifischer Kamerasteuerung-->
		<script type="text/javascript" src="libs/OrbitControls.js"></script>
		<!-- Include von Standardmaterialien in Form von Three.js-Materialien-->
		<script type="text/javascript" src="libs/MatLibThree.js"></script>
		<!-- Include von Standardmaterialien in Form von physi.js-Materialien-->
		<script type="text/javascript" src="libs/MatLibPhysi.js"></script>
		<!-- Include von KeyboardState.js zur Aufnahme von Tastatureingaben-->
		<script type="text/javascript" src='libs/THREEx.KeyboardState.js'></script>

		<!--Source-Code der Anwendung-->
		<script type="text/javascript">
			'use strict';

			// Web workers Referenz fuer Physijs zur Nutzung in Hintergrund-Thread
			Physijs.scripts.worker = 'libs/physijs_worker.js';
			// Link zur intern verwendeten Ammo.js-Library
			Physijs.scripts.ammo = '../libs/ammo.js';

			// Three.js-Hilfsmittel zur Zeiterfassung
			var clock = new THREE.Clock();
			// Referenz auf Tastatur laesst sich mit tastatur.destroy() wieder deaktivieren
			var tastatur = new THREEx.KeyboardState();
			//var scale = chroma.scale(['white', 'blue', 'red', 'yellow']);

			var initScene;
			var render;
			var ground_material;
			var box_material;
			var renderer;
			var render_stats;
			var physics_stats;
			var szene;
			var fahrbahn;
			var light;
			var kamera;

			var orbitControls;
			var fahrzeug;
			var car_material;
			var karosserie;
			var mesh;
			var gui;
			var steuerung;
			var skyBox;
			var cubeCamera;
			
			var direktionalesLicht;

			var umgebungsElementZaehler = 0;


			initScene = function() {
				if (window.WebGLRenderingContext) {
					renderer = new THREE.WebGLRenderer({
						antialias : true
					});
				} else {
					renderer = new THREE.CanvasRenderer();
				}

				// Renderer auf die Groesse des Fensters maximieren
				renderer.setSize(window.innerWidth, window.innerHeight);
				// Hintergrundfarbe des Renderers festlegen
				renderer.setClearColor(0x000000);
				// shadowMaps aktivieren
				renderer.shadowMapEnabled = true;

				document.getElementById('viewport').appendChild(renderer.domElement);

				// Anzeige zur Kontrolle der Performance des Rendering erstellen, positionieren, anhaengen
				render_stats = new Stats();
				render_stats.domElement.style.position = 'absolute';
				render_stats.domElement.style.top = '1px';
				render_stats.domElement.style.left = '1px';
				render_stats.domElement.style.zIndex = 100;
				document.getElementById('viewport').appendChild(render_stats.domElement);

				// Anzeige zur Kontrolle der Perfomance im Hintegrund-Thread der Physikberechnung erstellen, positionieren, anhaengen
				physics_stats = new Stats();
				physics_stats.domElement.style.position = 'absolute';
				physics_stats.domElement.style.top = '50px';
				physics_stats.domElement.style.zIndex = 100;
				document.getElementById('viewport').appendChild(physics_stats.domElement);

				// szene als Physijs-szene erstellen
				szene = new Physijs.Scene({
					// Speichert die Objektdaten und sollte zu Performancezwecken auf Objektzahl reduziert werden
					reportSize : 1000,
					// Einflussgroesser zur Berrechnungszeit der Physik. Kleinerer Wert, genaueres Ergebnis, schlechtere Performance
					fixedTimeStep : 1 / 120
				});

				// Schwerkraft in -Y ggf. auf Vorlagedaten anpassen
				szene.setGravity(new THREE.Vector3(0, -60, 0));

				// Kamera mit Brennweite, Seitenverhaeltniss, Near- und Far-Plane
				kamera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 1, 1000);
				// Anfangsposition der Kamera (Fahrzeugverfolgung ueberschreibt entsprechend)
				kamera.position.set(45, 45, 45);
				szene.add(kamera);

				//orbitControls = new THREE.OrbitControls(kamera);
				//orbitControls.autoRotate = false;

				// Skybox erzeugen
				var cubeMap = erstelleSkyBox();
				var shader = THREE.ShaderLib["cube"];
				shader.uniforms["tCube"].value = cubeMap;
				var material = new THREE.ShaderMaterial({
					fragmentShader : shader.fragmentShader,
					vertexShader : shader.vertexShader,
					uniforms : shader.uniforms,
					depthWrite : false,
					side : THREE.BackSide
				});

				skyBox = new THREE.Mesh(new THREE.CubeGeometry(1000, 1000, 1000), material);

				setupReflections();

				szene.add(skyBox);

				erstelleUmgebungsElement();
				createCar();

				erstelleHemisphereLight();
				// Light
				light = new THREE.SpotLight(0xFFFFFF);
				light.position.set((20 + umgebungsElementZaehler * 100), 100, -20);
				light.castShadow = true;
				light.shadowMapDebug = true;
				light.shadowCameraNear = 1;
				light.shadowCameraFar = 250;
				light.shadowCameraVisible = true;
				//szene.add(light);

				// NEU
				direktionalesLicht = new THREE.DirectionalLight(0xffffff);
				direktionalesLicht.position.set(-40, 60, -10);
				direktionalesLicht.castShadow = true;
				direktionalesLicht.shadowCameraVisible = true;
				direktionalesLicht.shadowCameraNear = 2;
				direktionalesLicht.shadowCameraFar = 200;
				direktionalesLicht.shadowCameraLeft = -50;
				direktionalesLicht.shadowCameraRight = 50;
				direktionalesLicht.shadowCameraTop = 50;
				direktionalesLicht.shadowCameraBottom = -50;

				direktionalesLicht.distance = 0;
				direktionalesLicht.intensity = 1.0;
				direktionalesLicht.shadowMapHeight = 1024;
				direktionalesLicht.shadowMapWidth = 1024;

				szene.add(direktionalesLicht);

			};
			/* Globales Licht-Hilfsmittel aus Three.js, dass realistischeren Eindruck schafft.*/
			function erstelleHemisphereLight() {
				// 1.Parameter: Farbton des direktional von +Y emittierten Licht (blau fuer Himmel).
				// 2. Parameter: Scheinbare Reflektion vom Boden.
				// 3. Parameter: Intensitaet der Lichtquelle
				var hemiLight = new THREE.HemisphereLight(0xaaaaaa, 0xdddddd, 0.6);
				// Positionierung
				hemiLight.position.set(0, 500, 0);
				// Wie andere Lichtquelle ueber visible aktivieren
				hemiLight.visible = true;
				// Wie andere Lichtquellen zur szene hinzufuegen
				szene.add(hemiLight);
			}

			/*Funktion um ein Rad an uebergebener Position zu erzeugen*/
			function createWheel(position) {
				/*Einzelteile (Materialen und Geometrien) einladen*/
				// Three.js-Materialien aus MatLibThree.js laden und ggf. in Physijs ergaenzen
				var wheel_material = Physijs.createMaterial(pChromeT, 1.0, .5);
				// Rad-Geometrie
				var wheel_geometry = new THREE.CylinderGeometry(2, 2, 2, 16);

				/*Einzelteile (Materialen und Geometrien) zu Mesch zusammenfügen*/
				// Rad-Mesh durch Verbindung von Geometrie und Materialien erzeugen
				var rad = new Physijs.CylinderMesh(wheel_geometry, wheel_material, 200);
				// Schattenwurf aktivieren
				rad.castShadow = true;

				/*Positionierung*/
				// Rotation je nach vorliegenden Objektdaten
				rad.rotation.x = Math.PI / 2;
				// Rad-Positionierung durch uebergebenen Parameter
				rad.position = position;
				// Rad an Aufrufer zurueckliefern
				return rad;
			}

			function createCar() {
				/*Einzelteile (Materialien und Geometrien einladen)*/
				// Three.js-Materialien aus MatLibThree.js laden

				// Geometrie mittels Loader einlesen
				var loader = new THREE.JSONLoader();
				// Referenz auf Datei und Callback-Funktion
				loader.load('assets/models/cube98306.js', function(geometry) {
					// Mesh aus Geometrie und Material erzeugen
					karosserie = new Physijs.BoxMesh(geometry, pRedT, 2000);
					// Schattenwurf aktivieren
					karosserie.castShadow = true;
					// Schattenwurf aktivieren
					karosserie.receiveShadow = true;
					// Ggf. Mesh positionieren
					karosserie.position.set(0, 5, 0);
					// Mesh zur szene hinzufuegen
					szene.add(karosserie);

					fahrzeug = {};

					// Raeder an Parameterposition erzeugen und in szene einfuegen
					var Hinten_links = createWheel(new THREE.Vector3(-5, 4, 5));
					szene.add(Hinten_links);
					var Hinten_rechts = createWheel(new THREE.Vector3(-5, 4, -5));
					szene.add(Hinten_rechts);
					var Vorne_links = createWheel(new THREE.Vector3(5, 4, 5));
					szene.add(Vorne_links);
					var Vorne_rechts = createWheel(new THREE.Vector3(5, 4, -5));
					szene.add(Vorne_rechts);

					// Constraints erzeugen und in Szene einfuegen
					var Hinten_linksConstraint = createWheelConstraint(Hinten_links, karosserie, new THREE.Vector3(-5, 4, 3));
					szene.addConstraint(Hinten_linksConstraint);
					var Hinten_rechtsConstraint = createWheelConstraint(Hinten_rechts, karosserie, new THREE.Vector3(-5, 4, -3));
					szene.addConstraint(Hinten_rechtsConstraint);
					var Vorne_linksConstraint = createWheelConstraint(Vorne_links, karosserie, new THREE.Vector3(5, 4, 3));
					szene.addConstraint(Vorne_linksConstraint);
					var Vorne_rechtsConstraint = createWheelConstraint(Vorne_rechts, karosserie, new THREE.Vector3(5, 4, -3));
					szene.addConstraint(Vorne_rechtsConstraint);

					/* Die Vorderreifen werden in X und Y beschraenkt.
					 * Nur eine Drehung um Z soll moeglich sein.
					 * Eine groesserer Wert im Unteren Limit als im Oberen, hebt das Limit auf.
					 * Identische Werte in beiden Limits fixieren die Position.*/
					Vorne_linksConstraint.setAngularLowerLimit({
						x : 0,
						y : 0,
						z : 0.1
					});
					Vorne_linksConstraint.setAngularUpperLimit({
						x : 0,
						y : 0,
						z : 0
					});
					Vorne_rechtsConstraint.setAngularLowerLimit({
						x : 0,
						y : 0,
						z : 0.1
					});
					Vorne_rechtsConstraint.setAngularUpperLimit({
						x : 0,
						y : 0,
						z : 0
					});

					/* Die Hinterreifen werden zunaechst in XYZ fixiert.
					 * Z wird zwar zur Drehung benoetigt, doch ueberschreibt der
					 * im Anschluss konfiguerierte Motor einen Wert nach Bedarf.*/
					Hinten_linksConstraint.setAngularLowerLimit({
						x : 0,
						y : 0,
						z : 0
					});
					Hinten_linksConstraint.setAngularUpperLimit({
						x : 0,
						y : 0,
						z : 0
					});
					Hinten_rechtsConstraint.setAngularLowerLimit({
						x : 0,
						y : 0,
						z : 0
					});
					Hinten_rechtsConstraint.setAngularUpperLimit({
						x : 0,
						y : 0,
						z : 0
					});

					// Antrieb an Hinterraedern durch Motor an Y-Achse
					Hinten_rechtsConstraint.configureAngularMotor(2, 0.1, 0, 0, 1500);
					Hinten_linksConstraint.configureAngularMotor(2, 0.1, 0, 0, 1500);

					// NEU NEU NEU
					Vorne_rechtsConstraint.configureAngularMotor(2, 0.1, 0, 0, 1500);
					Vorne_linksConstraint.configureAngularMotor(2, 0.1, 0, 0, 1500);

					// Constraints in neue entsprechende Variablen des Fahrzeugs uebergeben
					fahrzeug.Hinten_rechtsConstraint = Hinten_rechtsConstraint;
					fahrzeug.Hinten_linksConstraint = Hinten_linksConstraint;
					fahrzeug.Vorne_rechtsConstraint = Vorne_rechtsConstraint;
					fahrzeug.Vorne_linksConstraint = Vorne_linksConstraint;

					// Karosserie in neue entsprechende Variable des Fahrzeugs uebergeben
					fahrzeug.karosserie = karosserie;

					steuerung = new function () {
					this.geschwindigkeit = 0;
					this.radEinschlag = 0.0000;

					this.loosenXRight = 0.0001;
					this.loosenXLeft = 0.0001;

					this.aktualisiereGeschwindigkeit = function () {
					// if you add a motor, the current constraint is overridden
					// if you want to rotate set min higher then max
					fahrzeug.Hinten_rechtsConstraint.configureAngularMotor(2, 0.1, 0, steuerung.geschwindigkeit, 15000);
					fahrzeug.Hinten_linksConstraint.configureAngularMotor(2, 0.1, 0, steuerung.geschwindigkeit, 15000);

					// NEU NEU NEU
					fahrzeug.Vorne_rechtsConstraint.configureAngularMotor(2, 0.1, 0, steuerung.geschwindigkeit, 15000);
					fahrzeug.Vorne_linksConstraint.configureAngularMotor(2, 0.1, 0, steuerung.geschwindigkeit, 15000);

					// motor two is forward and backwards
					fahrzeug.Hinten_rechtsConstraint.enableAngularMotor(2);
					fahrzeug.Hinten_linksConstraint.enableAngularMotor(2);
					fahrzeug.Vorne_rechtsConstraint.enableAngularMotor(2);
					fahrzeug.Vorne_linksConstraint.enableAngularMotor(2);
					}

					this.aktualisiereRadEinschlag = function () {
					fahrzeug.Vorne_linksConstraint.setAngularLowerLimit({ x: 0, y: steuerung.radEinschlag, z: 0.1 });
					fahrzeug.Vorne_linksConstraint.setAngularUpperLimit({ x: steuerung.loosenXRight, y: steuerung.radEinschlag, z: 0 });
					fahrzeug.Vorne_rechtsConstraint.setAngularLowerLimit({ x: steuerung.loosenXLeft, y: steuerung.radEinschlag, z: 0.1 });
					fahrzeug.Vorne_rechtsConstraint.setAngularUpperLimit({ x: 0, y: steuerung.radEinschlag, z: 0 });
					}

					};

					gui = new dat.GUI();
					gui.add(steuerung, 'geschwindigkeit', -15, 15).onChange(steuerung.aktualisiereGeschwindigkeit);
					gui.add(steuerung, 'radEinschlag', -1.000, 1.000).onChange(steuerung.aktualisiereRadEinschlag);
					//gui.add(steuerung, 'loosenXRight', 0, 0.5).step(0.01).onChange(steuerung.aktualisiereRadEinschlag);
					//gui.add(steuerung, 'loosenXLeft', 0, 0.6).step(-0.01).onChange(steuerung.aktualisiereRadEinschlag);
					steuerung.loosenXLeft = 0;
					steuerung.loosenXRight = 0;

					requestAnimationFrame(render);

					szene.simulate();
					return fahrzeug;

				});
			}

			/* Funktion die das Rad (1.) an der Karosserie (2.) an Position (3.) fixiert*/
			function createWheelConstraint(rad, karosserie, position) {
				// "Degree of Freedom"-Constraint erlaubt die Beschraenkung der Rotation
				var constraint = new Physijs.DOFConstraint(rad, karosserie, position);

				return constraint;
			}

			/* Funktion zum erstellen eines neuen Umgebungsabschnitts*/
			function erstelleUmgebungsElement() {
				
				// Physijs-Material fuer Strasse
				var ground_grey = Physijs.createMaterial(pGreyT, 1, .7);
				
				var length = 100;
				var fahrbahnBreite = 25;

				var gruppe = new Physijs.BoxMesh(new THREE.CubeGeometry(0,0,0),lRedT,0);

				// Untergrund
				var Untergrund = new Physijs.BoxMesh(new THREE.CubeGeometry(length, 1, fahrbahnBreite * 4), ground_grey, 0);
				Untergrund.receiveShadow = true;
				Untergrund.position.y = -0.1;
				Untergrund.position.x = 0 + umgebungsElementZaehler * 100;
				Untergrund.position.z = 5;
				Untergrund.receiveShadow = true;

				gruppe.add(Untergrund);
				


				// Physikalischer Untergrund (wegen Reibung) ohne Masse (um ihn in der Welt zu fixieren)
				fahrbahn = new Physijs.BoxMesh(new THREE.CubeGeometry(length, 1, fahrbahnBreite), ground_grey, 0);
				// Positionierung entsprechend vorangegangener Elemente
				fahrbahn.position.x = 0 + umgebungsElementZaehler * 100;
				// Mit vorliegenden Daten abstimmen
				fahrbahn.position.z = 0;
				// Schatten empfangen aktivieren
				fahrbahn.receiveShadow = true;
				
				gruppe.add(fahrbahn);
				// Zur szene hinzufuegen
				//szene.add(fahrbahn);

				//
				var triggerRechts = new Physijs.BoxMesh(new THREE.CubeGeometry(length, 5, 2), lRedT, 0);
				var triggerLinks = new Physijs.BoxMesh(new THREE.CubeGeometry(length, 5, 2), lBlueT, 0);

				// Positionieren der Trigger anhand der Fahrbahnbreite und Schattenempfang aktivieren
				triggerRechts.position.x = umgebungsElementZaehler * 100;
				triggerRechts.position.z = -3 + fahrbahnBreite / 2;
				triggerRechts.position.y = 2;
				triggerRechts.rotation.y = .05;
				triggerRechts.receiveShadow = true;
				triggerLinks.position.x = umgebungsElementZaehler * 100;
				triggerLinks.position.z = 3 - (fahrbahnBreite / 2);
				triggerLinks.position.y = 2;
				triggerLinks.rotation.y = -.05;
				triggerLinks.receiveShadow = true;

				// Eventlistener an Trigger binden
				triggerRechts.addEventListener('collision', function() {
					//alert("Lane-Assist");
					szene.remove(this);
					if (!tastatur.pressed("D")) {
						if (steuerung.radEinschlag < 0) {
							steuerung.radEinschlag = steuerung.radEinschlag * -.8;
						}
						if (steuerung.radEinschlag == 0) {
							steuerung.radEinschlag = 0.1;
						}
						steuerung.aktualisiereRadEinschlag();
					}
				});

				// Eventlistener an Trigger binden
				triggerLinks.addEventListener('collision', function() {
					//alert("Lane-Assist");
					szene.remove(this);
					if (!tastatur.pressed("A")) {
						if (steuerung.radEinschlag > 0) {
							steuerung.radEinschlag = steuerung.radEinschlag * -.8;
						}
						if (steuerung.radEinschlag == 0) {

							steuerung.radEinschlag = -0.1;
						}
						steuerung.aktualisiereRadEinschlag();
					}
				});

				// Hinzufuegen der Trigger zur szene
				gruppe.add(triggerRechts);
				gruppe.add(triggerLinks);


				szene.add(Untergrund);

				// Dekoration

				for (var i = 0; i <= zufallszahl(10, 30); i++) {
					var boxGeometrie = new THREE.CubeGeometry(zufallszahl(20, 40), zufallszahl(10, 50), zufallszahl(10, 20));
					var box = new THREE.Mesh(boxGeometrie, pWhiteT);
					box.position.x = zufallszahl(-50, 50) + umgebungsElementZaehler * 100;

					if (zufallszahl(0, 1) > 0.5) {
						box.position.z = zufallszahl(40, 50);
					} else {
						box.position.z = zufallszahl(-30, -40);
					}
					box.castShadow = true;
					box.receiveShadow = true;

					gruppe.add(box);
				}

				szene.add(gruppe);
				umgebungsElementZaehler++;
			}

			function zufallszahl(min, max) {
				return (Math.random() * (max - min)) + min;
			}

			/* Materialien aus der angefertigten Standardbibliothek, die zusätzliche szenenabhaengige Ressourcen erfordern,
			 werden in dieser Funktion initialisiert.*/
			function setupReflections() {
				pChromeT.envMap = skyBox;
			}

			/* Funktion zum Einlesen von Tastatureingaben zur Steuerung des Fahrzeugs*/
			function steuern() {

				// Aktualisieren aller datGUI-Steuerungselemente
				for (var i in gui.__controllers) {
					gui.__controllers[i].updateDisplay();
				}
				// Beschleunigen
				if (tastatur.pressed("W") && steuerung.geschwindigkeit > -15) {
					steuerung.geschwindigkeit -= 0.25;
					// Falls nicht gelenkt wird, den Einschlag aufheben
					if (!tastatur.pressed("A") && !tastatur.pressed("D") && steuerung.radEinschlag != 0) {
						steuerung.radEinschlag *= 0.8;
					}
				}
				// Abbremsen
				if (tastatur.pressed("S") && steuerung.geschwindigkeit < 15) {
					if(steuerung.geschwindigkeit<0){steuerung.geschwindigkeit += 0.25;
					// Falls nicht gelenkt wird, den Einschlag aufheben
					if (!tastatur.pressed("A") && !tastatur.pressed("D") && steuerung.radEinschlag != 0) {
						steuerung.radEinschlag *= 0.8;
					}}
				}
				// Links
				if (tastatur.pressed("A") && steuerung.radEinschlag < .3) {
					steuerung.radEinschlag += 0.01;
				}
				// Rechts
				if (tastatur.pressed("D") && steuerung.radEinschlag > -.3) {
					steuerung.radEinschlag -= 0.01;
				}
				// Handbremse
				if (tastatur.pressed("space")) {
					steuerung.geschwindigkeit *= 0;
				}

				/* Einkommentieren falls das Fahrzeug ausrollen soll / man manuell Gas geben koennen soll*/
				//if (!tastatur.pressed("W") && !tastatur.pressed("S") && steuerung.geschwindigkeit != 0) {
				//steuerung.geschwindigkeit *= 0;
				//}
				//steuerung.radEinschlag *=.95;

				steuerung.aktualisiereGeschwindigkeit();
				steuerung.aktualisiereRadEinschlag();
			}

			/* Funktion zum Erstellen einer Skybox durch Projektino von 6 Bildern UF Wuerfel.*/
			function erstelleSkyBox() {
				// Referenz auf Ordner der Cubemap Bilder
				var pfad = "assets/textures/cubemap/UnionSquare/";
				// Dateiformat
				var format = '.jpg';
				// Array mit Referenzen auf alle Bilder zum uebergeben an THREE.ImageUtils.loadTextureCube()
				var urls = [pfad + 'posx' + format, pfad + 'negx' + format, pfad + 'posy' + format, pfad + 'negy' + format, pfad + 'posz' + format, pfad + 'negz' + format];
				// Three.js-Hilfsmittel zum Erzeugen der skyBox aus dem Dateipfaden-Array
				skyBox = THREE.ImageUtils.loadTextureCube(urls, new THREE.CubeReflectionMapping());
				// skyBox an Aufrufer zurueckgeben
				return skyBox;
			}

			/* Mit Bewegungsfortschritt neue Umgebungsgeometrie erzeugen*/
			function aktualisiereWelt() {
				// Sobald das Fahrzeug eine gewisse Distanz im Verhaetniss zur Laenge eines Umgebungselemts zurueckgelegt hat
				if (fahrzeug.karosserie.position.x > 10 + 100 * (umgebungsElementZaehler - 1)) {
					// muss ein neues Umgebungselement erstellt werden, das die Fahrbahn fortsetzt.
					erstelleUmgebungsElement();
				}
				// skyBox bewegt sich mit dem Fahrzeug mit um nicht zu enden
				skyBox.position.x = fahrzeug.karosserie.position.x;
				
				
				direktionalesLicht.position.set( fahrzeug.karosserie.position.x - 40, 50, fahrzeug.karosserie.position.z - 40);
				direktionalesLicht.target.position.set( fahrzeug.karosserie.position.x, fahrzeug.karosserie.position.y, fahrzeug.karosserie.position.z );
			}

			/*Renderloop der Anwenung*/
			render = function() {

				// Status (FPS oder MS) updaten
				render_stats.update();
				physics_stats.update();

				// Verstrichene Zeit messen
				var delta = clock.getDelta();

				// Steuerungseingaben auf Fahrzeug uebertragwen
				steuern();
				// Mit Bewegungsfortschritt neue Umgebungsgeometrie erzeugen
				aktualisiereWelt();
				// Cameraposition auf Hoehe des Fahrzeugs
				kamera.position.x = fahrzeug.karosserie.position.x + 45;
				// Camerafokus auf Fahrzeug
				kamera.lookAt(fahrzeug.karosserie.position);

				// Aufruf zum wiederholten Rendern
				requestAnimationFrame(render);
				// Welche szene mit welcher Kamera gerendert wird
				renderer.render(szene, kamera);

				/* Aufruf an Physijs Position, Rotation seiner Objekte zu aktualisieren
				 * Undefined legt dabei fest, dass soviel simuliert werden soll wie moeglich,
				 * maximal aber ueber die danach angegebenen 2 Iterationen.*/
				szene.simulate(undefined, 2);
			};
			// Zum Beginn initScene aufrufen
			window.onload = initScene;
		</script>
	</head>

	<body>
		<div id="viewport"></div>
	</body>

</html>
